import logging

from django.contrib.auth.models import User
from django.shortcuts import render
from django.views import View
from django_redis import get_redis_connection
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet, GenericViewSet, ReadOnlyModelViewSet
from rest_framework.permissions import IsAuthenticated
from rest_framework_extensions.cache.mixins import CacheResponseMixin

from config.dbs.redisconfig import KEY_TEMPLATE, EXPIRE_TIME
from users.models import Area, Address
from users.serializers import UserSerializer, MyTokenObtainSerializer, UserDetailSerializer, UpdatePasswordSerializer, \
    AreaSerializer, AddressSerializer, AreaChildSerializer
from utils.verifyUtil import ImageVerifyUtil
import io
from django.http import HttpResponse
from rest_framework_simplejwt.views import TokenObtainPairView
from fdfs_client.client import Fdfs_client, get_tracker_conf

#
# # 创建日志对象
logger = logging.getLogger('__name__')
# 创建fastdfs客户端对象
tracker_path = get_tracker_conf("fastdfs/client.conf")
# 通过配置文件地址 创建fastdfs的客户端
client = Fdfs_client(tracker_path)


# 图片验证码类视图 测试用的
#  127.0.0.1:8000/user/verification/uuid
class ImageVerifyView(View):
    # 客户端发送get 请求时
    # 返回出去
    def get(self, request, func, uuid):
        # 实例化 验证码工具类
        image_verify_util = ImageVerifyUtil()
        img, code = image_verify_util.verify_code()
        # 内存中
        # 字节流 临时存储 不会持久化数据
        img_byte = io.BytesIO()  # 创建一个临时的字节文件
        img.save(img_byte, format='PNG')  # 将图片保存到内存中
        # 读取字节数据 响应给客户端
        res = img_byte.getvalue()  # 读取文件内容
        # 存储进入redis 获取redis缓存对象
        cache = get_redis_connection(alias='verify_codes')
        # 通过redis缓存对象 进行set 存储数据
        cache.set(KEY_TEMPLATE % (func, uuid), code, EXPIRE_TIME)
        return HttpResponse(res, content_type='image/png')


# 注册类视图 与前端对应了
class UserViewSet(GenericViewSet):
    queryset = User.objects.all()
    serializer_class = UserSerializer

    # 重写序列化器的选择
    def get_serializer_class(self):
        if self.action == 'info':
            return UserDetailSerializer
        elif self.action == 'password':
            return UpdatePasswordSerializer
        else:
            return UserSerializer

    # 权限问题
    # now 方法只能登录的使用

    def get_permissions(self):
        if self.action in ['now', 'info']:
            # 就需要登录
            permissions_class = [IsAuthenticated]
        else:
            permissions_class = []
            # 后期可能存在其他的权限
        return [permission() for permission in permissions_class]

    # 修改用户详情 只能看自己的
    @action(methods=['get'], detail=False)
    def now(self, request):
        # 序列化返回数据到客户端
        serializer = self.get_serializer(request.user)
        return Response(serializer.data)

    # 创建用户
    # 重写父类的create方法 不需要权限
    def create(self, request, *args, **kwargs):
        # 进行反序列化
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        # 客户端数据
        username = request.data.get('username')
        password = request.data.get('password')
        # 进行持久化操作
        user = User(username=username)
        user.set_password(password)
        user.save()
        # 序列化 返回创建信息
        serializer = self.get_serializer(user)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    # 修改用户信息 肯定是当前的这个用户
    # 127.0.0.1:8000/user/users/info
    @action(methods=["put"], detail=False)
    def info(self, request):
        # 得到当前的用户信息
        user = request.user
        # 修改的是当前的用户  是否允许修改前端传入post提交的数据
        request.POST._mutable = True
        # user.id 得到的是当前登录的id
        request.data["user"] = user.id

        # 新增头像操作
        # 得到客户端传入的头像数据
        file = request.FILES.get('file')
        # 判断是否存在文件数据
        if file:
            # 判断是否是图片
            if file.content_type not in ['image/png', 'image/jpeg']:
                return Response(status=status.HTTP_400_BAD_REQUEST)
            try:
                # 如果没有文件后缀 1.png
                image_ext_name = file.name.split('.')[-1]  # ["1" , "png"]
            except Exception as e:
                logger.info(f"图片的扩展名异常{e}")
                image_ext_name = "png"
            # 进行持久化存储  storage（存储服务端）
            try:
                # upload_by_filename  ==> upload_by_buffer
                # 数据 和文件的后缀  ===》 storage  ===》xxxxxx.png
                uploade_res = client.upload_by_buffer(file.read(), file_ext_name=image_ext_name)
            except Exception as e:
                logger.error(f"图片上传出现异常{e}")
                return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            else:
                # 再进行数据库的持久化存储  图片地址
                if uploade_res.get("Status") != "Upload successed.":
                    logger.warning("图片上传失败")
                    return Response(status=status.HTTP_500_INTERNAL_SERVER_ERROR)
                else:
                    # 字节文件  ===》 字符文件
                    image_url = uploade_res.get("Remote file_id").decode()
                    request.data["avatar"] = image_url

        # 已经存在用户详情  修改
        if hasattr(user, "userdetail"):
            if user.userdetail.avatar:
                try:
                    client.delete_file(user.userdetail.avatar.encode())
                except Exception as e:
                    logger.error(f"Failed to delete old avatar: {e}")
            user_detail_serializer = self.get_serializer(instance=user.userdetail, data=request.data)
        else:
            # 没有用户详情  新增
            user_detail_serializer = self.get_serializer(data=request.data)
        user_detail_serializer.is_valid(raise_exception=True)
        user_detail_serializer.save()
        return Response(user_detail_serializer.data)

    @action(methods=['put'], detail=False)
    def password(self, request):
        user = request.user
        update_serializer = self.get_serializer(
            data=request.data)  # 等同于 serializer = UpdatePasswordSerializer(data=request.data)
        update_serializer.is_valid(raise_exception=True)
        # 校验原密码
        password = request.data.get('password')
        new_password = request.data.get('new_password')

        # 校验传入的新密码是否与数据库中密码一致 正确了才能修改新密码
        user.set_password(new_password)
        user.save()
        return Response({'msg': '密码修改成功'})


# 登录的视图逻辑
class MyTokenObtainViews(TokenObtainPairView):
    # 指定序列化器
    serializer_class = MyTokenObtainSerializer


# 地址视图　
# redis 有时效性的  热点数据
#       数据缓存操作  针对读取多  修改少的
# 只看查 不修改
# class AreaViewSet(GenericViewSet,ListModelMixin):
class AreaViewSet(CacheResponseMixin, ReadOnlyModelViewSet):
    queryset = Area.objects.all()
    serializer_class = AreaSerializer
    permission_classes = [IsAuthenticated]

    # 没有指定id查询 查所有一级分类
    # 重写查询集
    def get_queryset(self):
        if self.action == 'list':
            return Area.objects.filter(parent=None)
        else:
            return self.queryset

    def get_serializer_class(self):
        if self.action == 'list':
            return self.serializer_class
        else:
            return AreaChildSerializer


# 详情地址 需要增删改查
class AddressViewSet(ModelViewSet):
    # 查询集
    queryset = Address.objects.filter(is_delete=False)
    serializer_class = AddressSerializer
    permission_classes = [IsAuthenticated]

    # 重写父类的create方法 绑定用户
    def create(self, request, *args, **kwargs):
        # 允许修改前端post提交的数据
        if self.queryset.filter(is_delete=False).count() >= 5:
            return Response({
                "detail": "收货地址数量超过最大5个的限制"
            }, status=status.HTTP_400_BAD_REQUEST)
        request.POST._mutable = True
        request.data["user"] = request.user.id
        return ModelViewSet.create(self, request, *args, **kwargs)
